
#include "sw_timer.h"
#include <string.h>

void sw_timer_set_period(SW_TIMER_STRUCT* sw_timer, uint16_t period)
{
	if(period > 0){
		sw_timer->counter = 0;
		sw_timer->period = period;
	}
}

uint16_t sw_timer_get_period(SW_TIMER_STRUCT* sw_timer)
{
    return sw_timer->period;
}

void sw_timer_reset_counter(SW_TIMER_STRUCT* sw_timer)
{
    sw_timer->counter = 0;
}

uint16_t sw_timer_get_counter(SW_TIMER_STRUCT* sw_timer)
{
    return sw_timer->counter;
}

void sw_timer_enable(SW_TIMER_STRUCT* sw_timer)
{
	if(sw_timer->period > 0)
		sw_timer->state.enable = 1;
}

void sw_timer_disable(SW_TIMER_STRUCT* sw_timer)
{
    sw_timer->state.enable = 0;
}

uint8_t sw_timer_check_enable(SW_TIMER_STRUCT* sw_timer)
{
    return sw_timer->state.enable;
}

void sw_timer_reset_timeout(SW_TIMER_STRUCT* sw_timer)
{
    sw_timer->state.timeout = 0;
}

uint8_t sw_timer_check_timeout(SW_TIMER_STRUCT* sw_timer)
{
    return sw_timer->state.timeout;
}

void sw_timer_tick_handler(SW_TIMER_STRUCT* sw_timer, uint16_t ticks)
{
    uint32_t tick_temp;
    if((sw_timer->state.enable)&&(sw_timer->period > 0)){
        tick_temp = ticks + sw_timer->counter;
        while(1){
            if(tick_temp < sw_timer->period){
                break;
            }
            else{
                tick_temp -= sw_timer->period;
                sw_timer->state.timeout = 1;
            }
        }
        sw_timer->counter = tick_temp;

        if((sw_timer->period_timeout_callback)
            &&(sw_timer->state.timeout)){
            sw_timer->period_timeout_callback(sw_timer);
        } 
    }
}

void sw_timer_init(SW_TIMER_STRUCT* sw_timer,
					uint16_t period,
					void (*period_timeout_callback_handler)(SW_TIMER_STRUCT* sw_timer))
{
	sw_timer->period = period;
	sw_timer->counter = 0;
	sw_timer->period_timeout_callback = period_timeout_callback_handler;
	sw_timer->state.enable = 0;
	sw_timer->state.timeout = 0;
}


void sw_timer_group_tick_handler(SW_TIMER_GROUP_STRUCT* sw_timer_group, uint16_t ticks)
{
    static uint8_t i;
    if(ticks > 0){
        for (i = 0; i < sw_timer_group->sw_timer_num; i++) {
            sw_timer_tick_handler(&(sw_timer_group->sw_timer[i]), ticks);
        }
    }
}

void sw_timer_group_init(SW_TIMER_GROUP_STRUCT* sw_timer_group,
                               uint8_t sw_timer_group_sw_timer_num,
                               SW_TIMER_STRUCT* sw_timer_group_space)
{
	memset(sw_timer_group_space, 0, sizeof(SW_TIMER_STRUCT)*sw_timer_group_sw_timer_num);
    sw_timer_group->sw_timer_num = sw_timer_group_sw_timer_num;
    sw_timer_group->sw_timer_pointer = 0;
    sw_timer_group->sw_timer = sw_timer_group_space;
}

SW_TIMER_STRUCT* sw_timer_new(SW_TIMER_GROUP_STRUCT* sw_timer_group,
                                uint16_t period,
                                void (*period_timeout_callback_handler)(SW_TIMER_STRUCT* sw_timer))
{
    SW_TIMER_STRUCT* sw_timer;
	if(sw_timer_group->sw_timer_pointer < sw_timer_group->sw_timer_num){
//		sw_timer = &(sw_timer_group->sw_timer[sw_timer_group->sw_timer_pointer]);
		sw_timer = sw_timer_group->sw_timer + sw_timer_group->sw_timer_pointer;
        sw_timer_group->sw_timer_pointer++;
		sw_timer_init(sw_timer, period,
					period_timeout_callback_handler);
        return sw_timer;
    }
    else{
        return 0;
    }
}


